﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cartoons.Model;
using System.IO;
using System.Xml.Linq;
using System.Text.RegularExpressions;

namespace BookComposer
{
    class BooksXMLHelper
    {
        static BooksDBEntities db = new BooksDBEntities();

        public static IEnumerable<Book> ParseXMLFolder(string folderName,short Id)
        {
            var filesToProcess = Directory.GetFiles(folderName, "*.xml");
            var directory = new DirectoryInfo(folderName);

            foreach (var file in filesToProcess)
            {
                var xmlBook = XElement.Load(new FileStream(file, FileMode.Open)).Element("Document");

                var dbBook = new Book();
                db.AddToBooks(dbBook);

                dbBook.BookID = int.Parse(xmlBook.Element("DocId").Value);
                //  dbBook.DzcFileLocation = string.Concat(xmlBook.Element("Items").Elements("Item").Select(i => string.Format("{0};", i.Element("No").Value.Trim())));
                dbBook.DzcFileLocation = directory.Name;

                dbBook.BookName = xmlBook.Element("Name").Value.TrimStart();
                dbBook.Publisher = xmlBook.Element("Publisher").Value;
                dbBook.PublicationPlace = xmlBook.Element("PublPlace").Value;
                dbBook.PublicationYear = ParseInt(xmlBook.Element("PublYear").Value);
                dbBook.Size = xmlBook.Element("Size").Value;
                dbBook.ISBN = xmlBook.Element("ISBN").Value;
                dbBook.ISSN = xmlBook.Element("ISSN").Value;
                dbBook.Annotation = string.Concat(xmlBook.Elements("Annotation").Select(a => a.Value.Trim()));
                dbBook.AuthorTypeID = GetAuthorTypeID(xmlBook.Element("AuthorType").Value);
                dbBook.ResponsibilityStatements = XFieldValue(xmlBook, "Відомості про відповідальність");
                dbBook.NameExtraInfo = XFieldValue(xmlBook, "Додаткові відомості щодо назви");
                dbBook.ParallelName = XFieldValue(xmlBook, "Паралельна назва");
                dbBook.PublicationInfo = XFieldValue(xmlBook, "Відомості про видання");
                dbBook.PartIndex = ParseInt(XFieldValue(xmlBook, "Номер частини"));
                dbBook.PartName = XFieldValue(xmlBook, "Назва частини");
                dbBook.PublicationStartYear = ParseInt(XFieldValue(xmlBook, "Рік початку публікації"));
                dbBook.PublicationFinishYear = ParseInt(XFieldValue(xmlBook, "Рік кінця публікації"));
                dbBook.SeriesName = XFieldValue(xmlBook, "Назва серії");
                dbBook.ParallelSeriesName = XFieldValue(xmlBook, "Паралельна назва серії");
                dbBook.SeriesInfo = XFieldValue(xmlBook, "Відомості щодо назви серії");
                dbBook.SeriesResponsibilityInfo = XFieldValue(xmlBook, "Відомості про відповідальність серії");
                dbBook.SeriesNumber = ParseInt(XFieldValue(xmlBook, "Номер випуску серії"));
                dbBook.SeriesISSN = XFieldValue(xmlBook, "ISSN серії");
                dbBook.SubSeriesName = XFieldValue(xmlBook, "Назва підсерії");
                dbBook.SubSeriesNumber = ParseInt(XFieldValue(xmlBook, "Номер підсерії"));
                dbBook.Illustrations = XFieldValue(xmlBook, "Ілюстрації");
                dbBook.Bibliography = XFieldValue(xmlBook, "Бібліографія");
                dbBook.SupportMatherials = XFieldValue(xmlBook, "Супроводжувальні матеріали");
                dbBook.CommonRemarks = XFieldValue(xmlBook, "Загальні зауваження");
                dbBook.TitlePageIndex = Id;

                dbBook.DocTypeID = GetDocTypeID(xmlBook.Element("DocType").Element("Name").Value);

                foreach (var author in GetAuthors(xmlBook.Element("Author").Value, dbBook.AuthorTypeID))
                    dbBook.Authors.Add(author);

                foreach (var cardName in xmlBook.Element("Cards").Elements("Card").Select(c => c.Value).Where(v => !string.IsNullOrEmpty(v)))
                    dbBook.Cards.Add(GetCard(cardName));

            }
           
            db.SaveChanges();
            db.AcceptAllChanges();

            return db.Books;
        }

        private static Card GetCard(string cardName)
        {
            var card = db.Cards.SingleOrDefault(c => c.Value == cardName.Trim());

            if (card != null)
                return card;

            card = new Card() { Value = cardName.Trim() };
            db.AddToCards(card);
            db.SaveChanges();
            return card;
        }

        private static IEnumerable<Author> GetAuthors(string authorsString, int? authorType)
        {
            if (string.IsNullOrEmpty(authorsString))
                return new Author[] { };

            var author = db.Authors.SingleOrDefault(a => a.Name == authorsString.Trim());

            if (author != null)
                return new Author[] { author };
            author = new Author() { Name = authorsString.Trim() };
            db.AddToAuthors(author);
            db.SaveChanges();
            return new Author[] { author };
        }

        private static int GetAuthorTypeID(string authorTypeName)
        {
            switch (authorTypeName.Trim())
            {
                case "Person":
                    return 1;
                case "Organization":
                    return 2;
                case "Event":
                    return 3;
                default:
                    throw new ArgumentException();
            }
        }

        private static int GetDocTypeID(string docTypeName)
        {
            var docType = db.DocTypes.SingleOrDefault(d => d.DocTypeName == docTypeName.Trim());
            if (docType != null)
                return docType.DocTypeID;

            var lastId = db.DocTypes.OrderByDescending(d => d.DocTypeID).FirstOrDefault();

            int id;
            if (lastId == null) id = 1; else id = lastId.DocTypeID + 1;

            db.AddToDocTypes(new DocType() { DocTypeName = docTypeName, DocTypeID = id });
            db.SaveChanges();
            return id;
        }

        private static int? ParseInt(string input)
        {
            if (input == null)
                return null;

            int output;

            if (int.TryParse(new Regex(@"\d+").Match(input).Value, out output))
                return output;
            return null;
        }

        private static string XFieldValue(XElement xmlBook, string fieldName)
        {
            var fn = xmlBook.Element("XFields").Elements("XField").Where(el => el.Element("Name").Value.Trim() == fieldName).FirstOrDefault();
            return fn != null ? fn.Element("Value").Value : null;
        }
    }
}
